import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class main {

	public static void main(String[] args) {
		if (args.length < 1)
		{
			System.out.println("You forgot the parameter!");
			return;
		}
		
		
		String problemType = args[0];
		LimitedDepthSearch.BreakType searchType = LimitedDepthSearch.BreakType.Cut;
		
		int depthCounter = 0; 
		while (searchType == LimitedDepthSearch.BreakType.Cut)
		{
			searchType = problemType.equals("Cannibale") ? startCannibalsProblem(++depthCounter) : startFarmerProblem(++depthCounter);
		}
		
		if (searchType == LimitedDepthSearch.BreakType.Found)
		{
			RiverNode endRiverNode = LimitedDepthSearch.endNode;		
			ArrayList<RiverNode> RiverNodes = new ArrayList<RiverNode>();
			RiverNodes.add(endRiverNode);
			
			while (endRiverNode.parent != null) {
				endRiverNode = endRiverNode.parent;
				RiverNodes.add(endRiverNode);
			}
			
			Collections.reverse(RiverNodes);
			for (int i = 0; i < RiverNodes.size(); i++) {
				System.out.print("State " + i  + ":     ");
				
				printHashMap(RiverNodes.get(i).state.StateInternalProperties);
				System.out.println();
			}
		}
		else
		{
			System.out.println("It exists no way from begin to end!");
		}
	}
	
	private static LimitedDepthSearch.BreakType startFarmerProblem(int depthLimit)
	{
		ArrayList<State> invalidStates = getInvalidStatesFarmer();
		Problem prob = new Problem("Farmer", 1, 1, 2, invalidStates);
		
		State beginState = new State();
		beginState.StateInternalProperties = new HashMap<String, Integer>();
		beginState.StateInternalProperties.put("Farmer", 1);
		beginState.StateInternalProperties.put("Fox", 1);
		beginState.StateInternalProperties.put("Goose", 1);
		beginState.StateInternalProperties.put("Corn", 1);
		beginState.StateInternalProperties.put("Ship", 1);
		
		State endState = new State();
		endState.StateInternalProperties = new HashMap<String, Integer>();
		endState.StateInternalProperties.put("Farmer", 0);
		endState.StateInternalProperties.put("Fox", 0);
		endState.StateInternalProperties.put("Goose", 0);
		endState.StateInternalProperties.put("Corn", 0);
		endState.StateInternalProperties.put("Ship", 0);
		
		return LimitedDepthSearch.start(depthLimit, beginState, endState, prob);
	}
	
	private static ArrayList<State> getInvalidStatesFarmer()
	{
		ArrayList<State> invalidStates = new ArrayList<State>();
		State one = new State();
		one.StateInternalProperties = new HashMap<String, Integer>();
		one.StateInternalProperties.put("Farmer", 0);
		one.StateInternalProperties.put("Fox", 1);
		one.StateInternalProperties.put("Goose", 1);
		one.StateInternalProperties.put("Corn", 0);
		one.StateInternalProperties.put("Ship", 0);
		invalidStates.add(one);
		
		State two = new State();
		two.StateInternalProperties = new HashMap<String, Integer>();
		two.StateInternalProperties.put("Farmer", 0);
		two.StateInternalProperties.put("Fox", 1);
		two.StateInternalProperties.put("Goose", 1);
		two.StateInternalProperties.put("Corn", 1);
		two.StateInternalProperties.put("Ship", 0);
		invalidStates.add(two);
		
		State three = new State();
		three.StateInternalProperties = new HashMap<String, Integer>();
		three.StateInternalProperties.put("Farmer", 0);
		three.StateInternalProperties.put("Fox", 0);
		three.StateInternalProperties.put("Goose", 1);
		three.StateInternalProperties.put("Corn", 1);
		three.StateInternalProperties.put("Ship", 0);
		invalidStates.add(three);
		
		State four = new State();
		four.StateInternalProperties = new HashMap<String, Integer>();
		four.StateInternalProperties.put("Farmer", 1);
		four.StateInternalProperties.put("Fox", 0);
		four.StateInternalProperties.put("Goose", 0);
		four.StateInternalProperties.put("Corn", 1);
		four.StateInternalProperties.put("Ship", 1);
		invalidStates.add(four);
		
		State five = new State();
		five.StateInternalProperties = new HashMap<String, Integer>();
		five.StateInternalProperties.put("Farmer", 1);
		five.StateInternalProperties.put("Fox", 0);
		five.StateInternalProperties.put("Goose", 0);
		five.StateInternalProperties.put("Corn", 0);
		five.StateInternalProperties.put("Ship", 1);
		invalidStates.add(five);
		
		State six = new State();
		six.StateInternalProperties = new HashMap<String, Integer>();
		six.StateInternalProperties.put("Farmer", 1);
		six.StateInternalProperties.put("Fox", 1);
		six.StateInternalProperties.put("Goose", 0);
		six.StateInternalProperties.put("Corn", 0);
		six.StateInternalProperties.put("Ship", 1);
		invalidStates.add(six);
		
		return invalidStates;
	}

	private static LimitedDepthSearch.BreakType startCannibalsProblem(int depthLimit)
	{
		ArrayList<State> invalidStates = getInvalidStatesCannibals();
		Problem prob = new Problem("all", 3, 1, 2, invalidStates);
		
		State beginState = new State();
		beginState.StateInternalProperties = new HashMap<String, Integer>();
		beginState.StateInternalProperties.put("Cannibal", 3);
		beginState.StateInternalProperties.put("Missionar", 3);
		beginState.StateInternalProperties.put("Ship", 1);
		
		State endState = new State();
		endState.StateInternalProperties = new HashMap<String, Integer>();
		endState.StateInternalProperties.put("Cannibal", 0);
		endState.StateInternalProperties.put("Missionar", 0);
		endState.StateInternalProperties.put("Ship", 0);
		
		return LimitedDepthSearch.start(depthLimit, beginState, endState, prob);
	}
	
	private static ArrayList<State> getInvalidStatesCannibals() {
		ArrayList<State> invalidStates = new ArrayList<State>();
		State one = new State();
		one.StateInternalProperties = new HashMap<String, Integer>();
		one.StateInternalProperties.put("Cannibal", 3);
		one.StateInternalProperties.put("Missionar ", 2);
		one.StateInternalProperties.put("Ship", 0);
		
		State two = new State();
		two.StateInternalProperties = new HashMap<String, Integer>();
		two.StateInternalProperties.put("Cannibal", 3);
		two.StateInternalProperties.put("Missionar", 1);
		two.StateInternalProperties.put("Ship", 0);
		
		State three = new State();
		three.StateInternalProperties = new HashMap<String, Integer>();
		three.StateInternalProperties.put("Cannibal", 2);
		three.StateInternalProperties.put("Missionar", 1);
		three.StateInternalProperties.put("Ship", 0);
				
		State five = new State();
		five.StateInternalProperties = new HashMap<String, Integer>();
		five.StateInternalProperties.put("Cannibal", 0);
		five.StateInternalProperties.put("Missionar", 1);
		five.StateInternalProperties.put("Ship", 0);
		
		State six = new State();
		six.StateInternalProperties = new HashMap<String, Integer>();
		six.StateInternalProperties.put("Cannibal", 0);
		six.StateInternalProperties.put("Missionar", 2);
		six.StateInternalProperties.put("Ship", 0);
		
		State seven = new State();
		seven.StateInternalProperties = new HashMap<String, Integer>();
		seven.StateInternalProperties.put("Cannibal", 1);
		seven.StateInternalProperties.put("Missionar", 2);
		seven.StateInternalProperties.put("Ship", 0);
		
		State eight = new State();
		eight.StateInternalProperties = new HashMap<String, Integer>();
		eight.StateInternalProperties.put("Cannibal", 3);
		eight.StateInternalProperties.put("Missionar", 2);
		eight.StateInternalProperties.put("Ship", 1);
		
		State nine = new State();
		nine.StateInternalProperties = new HashMap<String, Integer>();
		nine.StateInternalProperties.put("Cannibal", 3);
		nine.StateInternalProperties.put("Missionar", 1);
		nine.StateInternalProperties.put("Ship", 1);
		
		State ten = new State();
		ten.StateInternalProperties = new HashMap<String, Integer>();
		ten.StateInternalProperties.put("Cannibal", 2);
		ten.StateInternalProperties.put("Missionar", 1);
		ten.StateInternalProperties.put("Ship", 1);
		
		State eleven = new State();
		eleven.StateInternalProperties = new HashMap<String, Integer>();
		eleven.StateInternalProperties.put("Cannibal", 0);
		eleven.StateInternalProperties.put("Missionar", 1);
		eleven.StateInternalProperties.put("Ship", 1);
		
		State twelve = new State();
		twelve.StateInternalProperties = new HashMap<String, Integer>();
		twelve.StateInternalProperties.put("Cannibal", 0);
		twelve.StateInternalProperties.put("Missionar", 2);
		twelve.StateInternalProperties.put("Ship", 1);
		
		State thirteen = new State();
		thirteen.StateInternalProperties = new HashMap<String, Integer>();
		thirteen.StateInternalProperties.put("Cannibal", 1);
		thirteen.StateInternalProperties.put("Missionar", 2);
		thirteen.StateInternalProperties.put("Ship", 1);
		
		invalidStates.add(one);
		invalidStates.add(two);
		invalidStates.add(three);
		invalidStates.add(five);
		invalidStates.add(six);
		invalidStates.add(seven);
		invalidStates.add(eight);
		invalidStates.add(nine);
		invalidStates.add(ten);
		invalidStates.add(eleven);
		invalidStates.add(twelve);
		invalidStates.add(thirteen);
		return invalidStates;
	}
	
	private static void printHashMap(Map<String, Integer> map)
	{
	    Iterator<String> iterator = map.keySet().iterator();  
	       
	    while (iterator.hasNext()) {  
	       String key = iterator.next().toString();  
	       String value = map.get(key).toString();  
	       
	       System.out.print(key + " " + value + " ; ");  
	    }  
	}

}
